<template>
	<view class="content bg">
		<z-paging class="" ref="paging" v-model="tempList" use-chat-record-mode safe-area-inset-bottom bottom-bg-color="#f8f8f8" @query="queryList" @keyboardHeightChange="keyboardHeightChange" @hidedKeyboard="hidedKeyboard">
			<!-- 顶部提示文字 -->
			<template #top>
				<!-- <view class="header">由于在H5、百度小程序、抖音小程序、飞书小程序中无法监听键盘高度变化，底部输入框切换时可能会有些bug，请运行在其他平台体验最佳效果</view> -->
			</template>
			<!-- v-if="requestState == 0" -->
			<!-- <view class="tip-ai-ing" v-if="requestState == 0" style="transform: scaleY(-1);">
				<text>AI正在思考中...</text>
			</view> -->
			<!-- for循环渲染聊天记录列表 -->
			<view v-for="(item,index) in tempList" :key="index" style="position: relative;">
				<!-- 如果要给聊天item添加长按的popup，请在popup标签上写style="transform: scaleY(-1);"，注意style="transform: scaleY(-1);"不要写在最外层，否则可能导致popup被其他聊天item盖住 -->
				<!-- <view class="popup" style="transform: scaleY(-1);">popUp</view> -->

				<!-- style="transform: scaleY(-1)"必须写，否则会导致列表倒置 -->
				<!-- 注意不要直接在chat-item组件标签上设置style，因为在微信小程序中是无效的，请包一层view -->

				<view style="transform: scaleY(-1);">
					<chat-item @changeAnswer="changeAnswer" :item="item"></chat-item>
				</view>
			</view>
			<!-- 底部聊天输入框 -->
			<template #bottom>
				<view class="foot-box" :style="{'padding-bottom': 'calc(60rpx + '+ btnbottom + 'px)'}">

					<view class="textarea-box">
						<textarea @focus="inputBindFocus" @blur="inputBindBlur" :show-confirm-bar="false" v-model="content" :cursor-spacing="15" class="textarea" :auto-height="true" placeholder="请输入要发送的内容" :maxlength="-1" :adjust-position="false" :disable-default-padding="false" placeholder-class="input-placeholder"></textarea>
					</view>
					<view class="send-btn-box">
						<image class="btn " style="opacity: 0.6;" v-if="requestState == 0" @click="stopDisconnect" src="https://dummyimage.com/74x74/346aff/ffffff?text=>" mode="widthFix"></image>
						<image class="btn " style="opacity: 0.6;" v-else-if=" !content" src="https://dummyimage.com/74x74/346aff/ffffff?text=>" mode="widthFix"></image>
						<image class="btn" v-else-if="content" @click="beforeSend(content)" src="https://dummyimage.com/74x74/346aff/ffffff?text=>" mode="widthFix"></image>
					</view>
				</view>
			</template>
		</z-paging>
	</view>
</template>

<script>
	import datalist from './index.js'

	var apiconfig = datalist.apiconfig
	export default {
		data() {sqlli
			return {
				btnbottom: 0,
				content: "",
				requestState: 1, //0思考中 1发送中 2发送成功 -1发送失败
				tempList: [],
			}
		},
		computed: {},
		onLoad(e) {},
		methods: {
			// 自定义请求  区分微信和h5 因为请求方法不一样
			getRequest(func) {
				let times = 0 //
				// #ifdef MP-WEIXIN
				// 这里打包请求
				const requestTask = uni.request({
					url: 'https://spark-api-open.xf-yun.com/v1/chat/completions', //仅为示例，并非真实接口地址。
					method: "post",
					enableChunked: true, // 开启流传输
					data: {
						temperature: apiconfig.temperature,
						top_p: apiconfig.top_p,
						"model": apiconfig.model,
						"user": apiconfig.user,
						"max_tokens": apiconfig.max_tokens,
						response_format: apiconfig.response_format,
						"messages": [
							...apiconfig.rolelist,
							...this.tempList.slice().reverse().map(item => ({ role: item.role, content: item.content }))
						],
						"stream": true //是否流式返回结果。
					},
					header: {
						'Authorization': 'Bearer tdbTiIGLYGjIxnWXiRaO:jsaKXUtKnngSjLRRSFuQ' //自定义请求头信息
					},
					timeout: 15000,
					success: response => {},
					fail: error => {
						console.log("请求失败：", error)
					}
				})
				// 这里监听消息 
				requestTask.onChunkReceived(function(res) {
					if (times === 0) { func && func('', 0) } //代表开始第一个
					times += 1
					const uint8Array = new Uint8Array(res.data);
					let text = String.fromCharCode.apply(null, uint8Array);
					text = decodeURIComponent(escape(text));
					try {
						text = text.replace('data: ', '');
						let textlist = text.split('data: ')
						// console.log('请求:', textlist)
						textlist.forEach((item => {
							if (item.includes('[DONE]')) {
								func && func('', 2) //代表结束
							} else {
								func && func(JSON.parse(item), 1) //代表发送中间数据
							}
						}))
					} catch (error) {
						func && func(text, 3) //代表报错
						// console.log("请求失败1：", text)
						// console.log("请求失败2：", error)
					}
					// 解析 JSON 字符串
				})
				// #endif
				// #ifdef H5
				console.log("请求对象：", apiconfig)

				const xhr = new XMLHttpRequest();
				xhr.open('POST', 'https://spark-api-open.xf-yun.com/v1/chat/completions');
				xhr.setRequestHeader('Authorization', 'Bearer tdbTiIGLYGjIxnWXiRaO:jsaKXUtKnngSjLRRSFuQ');
				// xhr.setRequestHeader('Content-Type', 'application/json');
				let textlength = 0
				// 请求接收数据
				xhr.onreadystatechange = function() {
					if (times === 0) { func && func('', 0) } //代表开始第一个
					times += 1

					let text = xhr.responseText.replace('data: ', '');
					if(text=='')return
					if (xhr.status === 200) {
						let textlist = text.split('data: ')
						let textlists = textlist.slice(textlength, textlist.length);
						textlength = textlist.length;
						textlists.forEach((item => {
							if (item.includes('[DONE]')) {
								func && func('', 2) //代表结束
							} else {
								if (item) {
									func && func(JSON.parse(item), 1) //代表发送中间数据
								}
							}
						}))
					} else if (xhr.readyState === 4 && xhr.status != 200) {
						func && func(text, 3) //代表报错
						// console.log("请求失败1：", text)
						// console.log("请求失败2：", xhr.statusText)
					}
				};
				// 下载监听已接收 ${event.loaded} 字节
				xhr.onprogress = function() {};
				xhr.onerror = function() { func && func('', 3) };
				const data = JSON.stringify({
					"model": apiconfig.model,
					"user": apiconfig.user,
					"messages": [
						...apiconfig.rolelist,
						...this.tempList.slice().reverse().map(item => ({ role: item.role, content: item.content }))
					],
					"stream": apiconfig.stream, //是否流式返回结果。

					"temperature": apiconfig.temperature,
					"top_p": apiconfig.top_p,
					"max_tokens": apiconfig.max_tokens,
					"response_format": apiconfig.response_format,


				});
				xhr.send(data);
				// #endif
			},

			// 发送新消息
			beforeSend(msg) {
				// uni.showLoading({
				// 	title: '发送中...'
				// })
				let mymsgdata = {
					name: "自己",
					'icon': '../../static/daxiong.jpg',
					"role": "user",
					content: msg //来一个只有程序员能听懂的笑话'
				}
				let yourmsgdata = {
					name: "大模型",
					'icon': '../../static/duola.jpg',
					"role": "assistant",
					status: 0, //1发送中 2发送成功 -1发送失败
					content: ''
				}
				this.tempList.unshift(mymsgdata)
				this.requestState = 0 //0思考中 1发送中 2发送成功 -1发送失败
				this.getRequest((text, type) => {
					this.content = ''
					// uni.hideLoading();
					// type 0 第一个 1 正常发送中间的 2 已结束 3 异常
					if (type === 0) {
						this.tempList.unshift(yourmsgdata)
						this.tempList[0].status = 1
						this.requestState = 1 //0思考中 1发送中 2发送成功 -1发送失败
					} else if (type === 1) {
						this.tempList[0].content += text.choices[0].delta.content
						console.log(text.choices[0].delta.content); // 输出解析后的对象
					} else if (type === 2) {
						this.tempList[0].status = 2
						this.requestState = 2 //0思考中 1发送中 2发送成功 -1发送失败
					} else if (type === 3) {
						this.tempList[0].status = -1
						this.requestState = -1 //0思考中 1发送中 2发送成功 -1发送失败
						uni.showToast({
							title: '请求失败',
							icon: 'none'
						})
					}
				})
			},


			isJSON(str) {
				if (typeof str === 'string') {
					try {
						const obj = JSON.parse(str);
						if (typeof obj === 'object' && obj) {
							return true;
						} else {
							return false;
						}

					} catch (e) {
						// console.log('error：'+str+'!!!'+e);
						return false;
					}
				}
			},
			//键盘高度适配
			inputBindBlur() {
				this.btnbottom = 0
			},
			//键盘高度适配
			inputBindFocus(e) {
				this.vipmsgShow = false
				// this.btnbottom = e.detail.height
			},
			queryList(pageNo, pageSize) {
				// 组件加载时会自动触发此方法，因此默认页面加载时会自动触发，无需手动调用
				// 这里的pageNo和pageSize会自动计算好，直接传给服务器即可
				// 模拟请求服务器获取分页数据，请替换成自己的网络请求
				// const params = {
				// 	pageNo: pageNo,
				// 	pageSize: pageSize,
				// }
				// if (pageNo >= 10) {
				// 	this.$refs.paging.complete(false);
				// } else {
				// 	this.$refs.paging.complete(this.tempList);
				// }
				// this.$request.queryChatList(params).then(res => {
				// 	// 将请求的结果数组传递给z-paging
				// 	this.$refs.paging.complete(res.data.list);
				// }).catch(res => {
				// 	// 如果请求失败写this.$refs.paging.complete(false);
				// 	// 注意，每次都需要在catch中写这句话很麻烦，z-paging提供了方案可以全局统一处理
				// 	// 在底层的网络请求抛出异常时，写uni.$emit('z-paging-error-emit');即可
				// 	this.$refs.paging.complete(false);
				// })
			},
			// 监听键盘高度改变，请不要直接通过uni.onKeyboardHeightChange监听，否则可能导致z-paging内置的键盘高度改变监听失效（如果不需要切换表情面板则不用写）
			keyboardHeightChange(res) {
				this.$refs.inputBar.updateKeyboardHeightChange(res);
			},
			// 用户尝试隐藏键盘，此时如果表情面板在展示中，应当通知chatInputBar隐藏表情面板（如果不需要切换表情面板则不用写）
			hidedKeyboard() {
				// this.$refs.inputBar.hidedKeyboard();
			},
		}
	}
</script>

<style>
	page {
		height: 100%;
	}
</style>
<style lang="scss" scoped>
	.tip-ai-ing {
		display: flex;
		align-items: center;
		flex-direction: column;
		font-size: 14px;
		color: #919396;
		padding: 15px 0;
	}
	.content {
		height: 100%;
	}
	.bg {
		// height: 100%;
		background-size: cover;
		background-color: #F5F6FA;
		background-image: url("");
	}
	.msg_fix {
		padding-top: 20rpx;
		flex-direction: column;
		.msg_greet {
			flex-direction: column;
			margin: 0 30rpx;
			padding: 32rpx 32rpx 36rpx 30rpx;
			background: #fff;
			border-radius: 0rpx 24rpx 24rpx 24rpx;
			font-size: 28rpx;
			.title {
				display: flex;
				color: rgba(32, 32, 32, 1);
				font-weight: 600;
				.icon {
					margin-right: 10rpx;
					flex-shrink: 0;
					width: 44rpx;
					height: 44rpx;
				}
				.text1 {
					display: flex;
					margin-bottom: 20rpx;
				}
			}
			.text {
				font-weight: 400;
				letter-spacing: 0rpx;
				line-height: 40rpx;
				color: rgba(119, 123, 161, 1);
			}
		}
		.msg_issue {
			flex-direction: column;
			font-size: 28rpx;
			margin: 32rpx 30rpx 0 30rpx;
			padding: 32rpx 30rpx 32rpx 30rpx;
			background: #fff;
			border-radius: 0rpx 24rpx 24rpx 24rpx;
			.msg_issue_header {
				display: flex;
				justify-content: space-between;
				margin-bottom: 2rpx;
				.title {
					color: rgba(32, 32, 32, 1);
					font-weight: bold;
					position: relative;
				}
				.msg_issue_cut {
					display: flex;
					align-items: center;
					.icon {
						width: 30rpx;
						height: 30rpx;
					}
					.text1 {
						display: flex;
						margin-left: 8rpx;
						color: rgba(119, 123, 161, 1)
					}
				}
			}
			.text2 {
				margin-right: 30rpx;
				overflow: hidden;
				text-overflow: ellipsis;
				display: -webkit-box;
				-webkit-box-orient: vertical;
				-webkit-line-clamp: 1;
				height: 80rpx;
				line-height: 80rpx;
			}
			.text2+.text2 {
				border-top: 1rpx solid rgba(235, 235, 235, 1);
			}
		}
		.divider {
			display: flex;
			color: #BBB9BE;
			font-size: 26rpx;
			margin: 20rpx 30rpx 20rpx 30rpx;
			align-items: center;
			.left {
				flex: 1;
				height: 1rpx;
				border-bottom: 1rpx solid #BBB9BE;
				transform: scaleY(0.5);
			}
			.text {
				margin: 0 20rpx;
				align-items: center;
				.icon {
					margin-left: 10rpx;
					width: 24rpx;
					height: 24rpx;
				}
			}
			.right {
				flex: 1;
				height: 1rpx;
				border-bottom: 1rpx solid #BBB9BE;
				transform: scaleY(0.5);
			}
		}
	}
	.foot-box {
		position: relative;
		width: 750rpx;
		box-sizing: border-box;
		display: flex;
		align-items: center;
		padding: 16rpx 28rpx 60rpx 30rpx;
		background-color: #FFF;
		.textarea-box {
			display: flex;
			flex: 1;
			padding: 0rpx 40rpx;
			box-sizing: border-box;
			align-items: center;
			min-height: 84rpx;
			border-radius: 42rpx;
			background: rgba(241, 241, 249, 1);
			.textarea {
				max-height: 120rpx;
				font-size: 14px;
				/* #ifndef APP-NVUE */
				overflow: auto;
				/* #endif */
				width: 100%;
				font-size: 14px;
			}
			.input-placeholder {
				///deep/
				color: rgba(164, 166, 191, 1);
			}
		}
		.send-btn-box {
			.btn {
				width: 74rpx;
				height: 74rpx;
				margin-left: 24rpx;
				animation: fadeInBig 0.2s 0.2s linear both;
			}
			@keyframes fadeInBig {
				0% {
					opacity: 0;
					transform: scale(0.5);
				}
				100% {
					transform: scale(1);
				}
			}
		}
	}
	.header {
		background-color: red;
		font-size: 20rpx;
		padding: 20rpx;
		color: white;
	}
	.popup {
		position: absolute;
		top: -20px;
		height: 200rpx;
		width: 400rpx;
		background-color: red;
		z-index: 1000;
	}
</style>